using Crux.Core.Dapper.SqlGenerator;
using Crux.Core.Dapper.SqlGenerator.Filters;

namespace Crux.Core.Dapper;
public partial class QueryRepository<TContext> where TContext : DapperContext
{
    /// <inheritdoc/>
    public TEntity? FirstOrDefault<TEntity>(
        Expression<Func<TEntity, bool>> predicate,
        bool ignoreFilter = false,
        Action<SqlGenerator<TEntity>>? configure = null,
        params Expression<Func<TEntity, object>>[] includes) where TEntity : class
    {
        var generator = GetSqlGenerator(configure);

        var sqlQuery = generator.GetSelectFirst(predicate, null, ignoreFilter: ignoreFilter, includes: includes);

        return QueryFirstOrDefault<TEntity>(sqlQuery.GetSql(), sqlQuery.Param);
    }
    /// <inheritdoc/>
    public TEntity? FirstOrDefault<TEntity>(
        Expression<Func<TEntity, bool>> predicate,
        Expression<Func<TEntity, object>> expr,
        bool ignoreFilter = false,
        Action<SqlGenerator<TEntity>>? configure = null,
        params Expression<Func<TEntity, object>>[] includes) where TEntity : class
    {
        var generator = GetSqlGenerator(configure);

        var filterData = new FilterData().BySelect(expr);

        var sqlQuery = generator.GetSelectFirst(predicate, filterData, ignoreFilter: ignoreFilter, includes: includes);

        return QueryFirstOrDefault<TEntity>(sqlQuery.GetSql(), sqlQuery.Param);
    }
    /// <inheritdoc/>
    public async Task<TEntity?> FirstOrDefaultAsync<TEntity>(
        Expression<Func<TEntity, bool>> predicate,
        bool ignoreFilter = false,
        Action<SqlGenerator<TEntity>>? configure = null,
        CancellationToken cancellationToken = default,
        params Expression<Func<TEntity, object>>[] includes) where TEntity : class
    {
        var generator = GetSqlGenerator(configure);

        var sqlQuery = generator.GetSelectFirst(predicate, null, ignoreFilter: ignoreFilter, includes: includes);

        return await QueryFirstOrDefaultAsync<TEntity>(sqlQuery.GetSql(), sqlQuery.Param, cancellationToken).ConfigureAwait(false);
    }
    /// <inheritdoc/>
    public async Task<TEntity?> FirstOrDefaultAsync<TEntity>(
        Expression<Func<TEntity, bool>> predicate,
        Expression<Func<TEntity, object>> expr,
        bool ignoreFilter = false,
        Action<SqlGenerator<TEntity>>? configure = null,
        CancellationToken cancellationToken = default,
        params Expression<Func<TEntity, object>>[] includes) where TEntity : class
    {
        var generator = GetSqlGenerator(configure);

        var filterData = new FilterData().BySelect(expr);

        var sqlQuery = generator.GetSelectFirst(predicate, filterData, ignoreFilter: ignoreFilter, includes: includes);

        return await QueryFirstOrDefaultAsync<TEntity>(sqlQuery.GetSql(), sqlQuery.Param, cancellationToken).ConfigureAwait(false);
    }

}